
import 'dart:async';

import 'package:flutter/cupertino.dart';

class RevolvingText extends StatefulWidget {

  /// the text that want to be show on the Widget
  final String text;

  /// the textStyle that the shown text has
  final TextStyle style;

  /// the revolving direction
  /// it can be horizontal or vertical
  final Axis scrollDirection;

  /// the ratio of blank
  /// while the widget is revolving,
  /// it need to show the part of text, and also the part of blank
  /// we can receive a double from 0 to 1
  /// that represent the ratio of blank to the meaningful part, such as text
  final double ratioOfBlank;

  /// the length of single movement
  final double moveDistance;

  /// refresh interval
  final int interval;

  RevolvingText({
    @required this.text,
    this.style,
    this.scrollDirection = Axis.horizontal,
    this.ratioOfBlank = 0.25,
    this.interval = 100,
    this.moveDistance = 3.0
  }) : assert(text != null);

  @override
  _RevolvingTextState createState() => _RevolvingTextState();

}

class _RevolvingTextState extends State<RevolvingText> {

  ScrollController _scrollController;

  /// the phones width
  /// use this value to determine the width of blank
  double _width;

  /// the phones height
  /// use this value to determine the height of blank
  double _height;

  /// position that scrollView should show
  double _position = 0.0;

  /// we use a timer to make the refresh work execute periodically
  Timer _timer;

  GlobalKey _key = GlobalKey();

  @override
  void initState() {
    super.initState();

    _scrollController = ScrollController();

    /// When the first time the widget had been rendered,
    /// it will call the method inside the queue [postFrameCallbacks].
    /// Here we use it to start our revolving controller.
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      startTimer();
    });
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();

    /// get the size of the Widget
    _width = MediaQuery.of(context).size.width;
    _height = MediaQuery.of(context).size.height;
  }

  @override
  void dispose() {
    super.dispose();
    _timer.cancel();
  }

  void startTimer(){

    /// get the size of the current widget
    double widgetWidth =
        _key.currentContext.findRenderObject().paintBounds.size.width;
    double widgetHeight =
        _key.currentContext.findRenderObject().paintBounds.size.height;

    /// start a periodic callback that make the widget revolve
    _timer = Timer.periodic(Duration(milliseconds:  widget.interval), (timer) {

      /// the max size that the scrollView can scroll
      double maxScrollableScope = _scrollController.position.maxScrollExtent;
      double pixels = _scrollController.position.pixels;

      /// if the widget has been completely shown,
      /// we should set the shown position to a specialized place that make the revolve seem more fluent
      /// the position value is been tested
      if(pixels + widget.moveDistance >= maxScrollableScope){
        if(widget.scrollDirection==Axis.horizontal){
          _position=(maxScrollableScope-_width*widget.ratioOfBlank-widgetWidth)/2+pixels-maxScrollableScope;
        }else{
          _position=(maxScrollableScope-_height*widget.ratioOfBlank-widgetHeight)/2+pixels-maxScrollableScope;
        }
        _scrollController.jumpTo(_position);
      }

      _position += widget.moveDistance;
      _scrollController.animateTo(
          _position,
          duration: Duration(milliseconds: widget.interval),
          curve: Curves.linear
      );
    });
  }

  Widget _content(){
    if(widget.scrollDirection == Axis.vertical){
      return Center(
        child: Text(
          widget.text.split("").join("\n"),
          style: widget.style,
          textAlign: TextAlign.center,
        ),
      );
    }
    return Center(
      child: Text(
        widget.text,
        style: widget.style,
      ),
    );
  }

  Widget _blank(){
    if(widget.scrollDirection == Axis.horizontal){
      return Container(width: _width*widget.ratioOfBlank);
    }
    return Container(height: _height*widget.ratioOfBlank);
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      key: _key,
      scrollDirection: widget.scrollDirection,
      controller: _scrollController,
      physics: NeverScrollableScrollPhysics(),
      children: [
        _content(),
        _blank(),
        _content()
      ],
    );
  }
}
